package com.youlu.campus.wechat.service.impl;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.cipher.AeadAesCipher;
import com.wechat.pay.java.core.http.AbstractHttpClient;
import com.wechat.pay.java.core.http.Constant;
import com.wechat.pay.java.core.http.DefaultHttpClientBuilder;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.core.http.HttpHeaders;
import com.wechat.pay.java.core.http.HttpMethod;
import com.wechat.pay.java.core.http.HttpRequest;
import com.wechat.pay.java.core.http.HttpResponse;
import com.wechat.pay.java.core.http.JsonRequestBody;
import com.wechat.pay.java.core.http.MediaType;
import com.wechat.pay.java.core.http.QueryParameter;
import com.wechat.pay.java.core.http.RequestBody;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
import com.wechat.pay.java.core.notification.RequestParam;
import com.youlu.campus.common.exception.BusinessException;
import com.youlu.campus.wechat.service.WechatComplaintService;
import com.youlu.campus.wechat.entity.ComplaintNotifyRequest;
import com.youlu.campus.wechat.entity.ComplaintNotifyResponse;
import com.youlu.campus.wechat.enums.WechatComplaintApiEnum;
import com.youlu.campus.wechat.utils.StringHashGenerator;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.complaint.MerchantComplaint;
import com.youlu.campus.entity.complaint.NotifyDecrypt;
import com.youlu.campus.entity.complaint.ReplyUserComplaint;
import com.youlu.campus.entity.complaint.vo.ComplaintHistoryResult;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import static com.wechat.pay.java.core.http.UrlEncoder.urlEncode;
import static com.wechat.pay.java.core.util.GsonUtil.toJson;
import static java.util.Objects.requireNonNull;

/**
 * 公钥模式- 微信商户投诉服务
 *
 * @Description: PubKeyWechatMerchantComplaintServiceImpl
 * @Date 2025/6/18
 * @author: su
 */
@Slf4j
public class PubKeyWechatComplaintServiceImpl implements WechatComplaintService {

    /**
     * mongodb 数据库配置验证 md5  避免重复创建
     */
    private final String configMD5;

    /**
     * 配置
     */
    private final Config config;

    /**
     * http客户端
     */
    private final HttpClient httpClient;

    /**
     * 通知回调解析器 验签、解密
     */
    private final NotificationParser parser;

    /**
     * 商户配置信息
     */
    private final WechatMerchantConfig wechatMerchantConfig;


    public PubKeyWechatComplaintServiceImpl(WechatMerchantConfig wechatMerchantConfig, String configMD5, Config config, HttpClient httpClient, NotificationParser parser) {
        this.wechatMerchantConfig = wechatMerchantConfig;
        this.configMD5 = configMD5;
        this.config = config;
        this.httpClient = httpClient;
        this.parser = parser;

    }

    @Override
    public String getConfigMD5() {
        return configMD5;
    }

    /**
     * 通知解析
     *
     * @param signatue
     * @param serialNo
     * @param nonce
     * @param timestamp
     * @param body
     * @return
     */
    @Override
    public NotifyDecrypt notifyParse(String signatue, String serialNo, String nonce, String timestamp, String body) throws Exception {
        log.info("notifyParse merchantId: {},merchantName: {}, httpResponse：{}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), body);
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signatue)
                .timestamp(timestamp)
                .body(body)
                .build();
        //解析
        NotifyDecrypt parse = parser.parse(requestParam, NotifyDecrypt.class);
        log.info("notifyParse result：{}", parse);
        return parse;
    }

    /**
     * 创建投诉通知回调地址
     *
     * @param url yyyy-MM-dd
     * @return
     */
    @Override
    public ComplaintNotifyResponse createNotifyUrl(String url) {
        log.info("createNotifyUrl merchantId: {},merchantName: {}, url：{}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), url);
        //验证不能为null
        requireNonNull(url);
        if (!url.startsWith("https://")) {
            throw new RuntimeException("通知地址，仅支持HTTPS");
        }
        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.CREATE_NOTIFY_URL;
        String requestPath = apiEnum.getUrl();

        //请求参数
        ComplaintNotifyRequest body = new ComplaintNotifyRequest();
        body.setUrl(url);

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath, body);
        //请求发送
        try {
            HttpResponse<ComplaintNotifyResponse> httpResponse = httpClient.execute(httpRequest, ComplaintNotifyResponse.class);
            log.info("createNotifyUrl httpResponse：{}", toJson(httpResponse));
            return httpResponse.getServiceResponse();
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }

    }

    /**
     * 查询投诉通知回调地址
     *
     * @return
     */
    @Override
    public ComplaintNotifyResponse getNotifyUrl() {
        log.info("getNotifyUrl merchantId: {},merchantName: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName());
        //验证不能为null
        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.QUERY_NOTIFY_URL;
        String requestPath = apiEnum.getUrl();

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath);
        try {
            //请求发送
            HttpResponse<ComplaintNotifyResponse> httpResponse = httpClient.execute(httpRequest, ComplaintNotifyResponse.class);
            log.info("getNotifyUrl httpResponse：{}", toJson(httpResponse));
            return httpResponse.getServiceResponse();
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 删除投诉通知回调地址
     *
     * @return
     */
    @Override
    public ComplaintNotifyResponse deleteNotifyUrl() {
        log.info("deleteNotifyUrl merchantId: {},merchantName: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName());
        //验证不能为null
        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.DELETE_NOTIFY_URL;
        String requestPath = apiEnum.getUrl();

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath);
        try {
            //请求发送
            HttpResponse<ComplaintNotifyResponse> httpResponse = httpClient.execute(httpRequest, ComplaintNotifyResponse.class);
            log.info("deleteNotifyUrl httpResponse：{}", toJson(httpResponse));
            return httpResponse.getServiceResponse();
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 查询 投诉列表
     *
     * @param beginDate yyyy-MM-dd
     * @param endDate   yyyy-MM-dd
     * @param limit
     * @param offset
     * @return
     */
    @Override
    public HashMap queryList(String beginDate, String endDate, Integer limit, Integer offset) {
        log.info("queryList merchantId: {},merchantName: {},beginDate: {},endDate: {},limit: {},offset: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), beginDate, endDate, limit, offset);
        //验证不能为null
        Stream.of(beginDate, endDate, limit, offset).forEach(Objects::requireNonNull);

        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.QUERY_COMPLAINT_LIST;
        String requestPath = apiEnum.getUrl();
        // 添加 query param
        QueryParameter queryParameter = new QueryParameter();
        queryParameter.add("begin_date", urlEncode(beginDate));
        queryParameter.add("end_date", urlEncode(endDate));
        queryParameter.add("limit", urlEncode(limit.toString()));
        queryParameter.add("offset", urlEncode(offset.toString()));
        //拼接请求参数
        requestPath += queryParameter.getQueryStr();

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath);
        //请求发送
        HttpResponse<HashMap> httpResponse = httpClient.execute(httpRequest, HashMap.class);
        log.info("queryList httpResponse: {}", httpResponse);
        return httpResponse.getServiceResponse();
    }

    /**
     * 查询投诉单详情 投诉单号
     *
     * @param complaintId
     * @return
     */
    @Override
    public MerchantComplaint queryDetail(String complaintId) {
        log.info("queryDetail merchantId: {},merchantName: {},complaintId: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), complaintId);
        //验证不能为null
        requireNonNull(complaintId);

        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.QUERY_COMPLAINT_DETAIL;
        String requestPath = apiEnum.getUrl(complaintId);

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath);
        //请求发送
        HttpResponse<MerchantComplaint> httpResponse = httpClient.execute(httpRequest, MerchantComplaint.class);
        log.info("queryDetail httpResponse: {}", httpResponse);
        return httpResponse.getServiceResponse();
    }

    @Override
    public ComplaintHistoryResult negotiationHistorys(String complaintId, Integer limit, Integer offset) {
        log.info("negotiationHistorys merchantId: {},merchantName: {},complaintId: {},limit: {},offset: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), complaintId, limit, offset);
        //验证参数不能为null
        Stream.of(complaintId, limit, offset).forEach(Objects::requireNonNull);

        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.QUERY_COMPLAINT_NEGOTIATION_HISTORY;
        String requestPath = apiEnum.getUrl(complaintId);
        // 添加 query param
        QueryParameter queryParameter = new QueryParameter();
        queryParameter.add("limit", urlEncode(limit.toString()));
        queryParameter.add("offset", urlEncode(offset.toString()));
        //拼接请求参数
        requestPath += queryParameter.getQueryStr();

        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), requestPath);
        //请求发送
        HttpResponse<ComplaintHistoryResult> httpResponse = httpClient.execute(httpRequest, ComplaintHistoryResult.class);
        log.info("negotiationHistorys httpResponse: {}", httpResponse);
        return httpResponse.getServiceResponse();
    }

    @Override
    public void response(ReplyUserComplaint replyUserComplaint) {
        log.info("response merchantId: {},merchantName: {},replyUserComplaint: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), replyUserComplaint);
        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.RESPONSE_COMPLAINT;
        //获取url
        String url = apiEnum.getUrl(replyUserComplaint.getComplaintId());
        //设置请求参数
        Map<String, Object> params = new HashMap<>();
        params.put("complainted_mchid", replyUserComplaint.getComplaintedMchid());
        params.put("response_content", replyUserComplaint.getResponseContent());
        params.put("response_images", replyUserComplaint.getResponseImages());
        params.put("jump_url", replyUserComplaint.getJumpUrl());
        params.put("jump_url_text", replyUserComplaint.getJumpUrlText());
        //请求发送
        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), url, params);
        HttpResponse<Object> httpResponse = httpClient.execute(httpRequest, Object.class);
        log.info("response httpResponse: {}", httpResponse);
    }

    @Override
    public void complete(String complaintId) {
        log.info("complete merchantId: {},merchantName: {},complaintId: {}", wechatMerchantConfig.getMerchantId(), wechatMerchantConfig.getMerchantName(), complaintId);
        WechatComplaintApiEnum apiEnum = WechatComplaintApiEnum.COMPLETE_COMPLAINT;
        //获取url
        String url = apiEnum.getUrl(complaintId);
        //设置请求参数
        Map<String, Object> params = new HashMap<>();
        params.put("complainted_mchid", this.wechatMerchantConfig.getMerchantId());
        //请求微信
        HttpRequest httpRequest = getHttpRequest(apiEnum.getMethod(), url, params);
        HttpResponse<Object> httpResponse = httpClient.execute(httpRequest, Object.class);
        log.info("complete httpResponse: {}", httpResponse);

    }

    /**
     * 获取http请求 体
     *
     * @param method
     * @param requestPath
     * @return
     */
    private HttpRequest getHttpRequest(HttpMethod method, String requestPath) {
        return getHttpRequest(method, requestPath, null);

    }

    /**
     * 获取http请求 体
     *
     * @param method
     * @param requestPath
     * @param body
     * @return
     */
    private HttpRequest getHttpRequest(HttpMethod method, String requestPath, Object body) {
        //设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
        if (Objects.nonNull(body)) {
            headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
        }
        //创建请求
        HttpRequest httpRequest = new HttpRequest.Builder()
                .httpMethod(method)
                .url(requestPath)
                .headers(headers)
                .body(createRequestBody(body))
                .build();
        return httpRequest;
    }

    /**
     * 创建请求体
     *
     * @param request
     * @return
     */
    private RequestBody createRequestBody(Object request) {
        if (Objects.isNull(request)) {
            return null;
        }
        return new JsonRequestBody.Builder().body(toJson(request)).build();
    }

    /**
     * builder 构造器
     */
    public static class Builder {

        private WechatMerchantConfig wechatMerchantConfig;

        public Builder config(WechatMerchantConfig wechatMerchantConfig) {
            this.wechatMerchantConfig = wechatMerchantConfig;
            return this;
        }

        public PubKeyWechatComplaintServiceImpl build() {
            log.info("PubKeyWechatComplaintServiceImpl Builder config:{}", wechatMerchantConfig);
            String merchantId = wechatMerchantConfig.getMerchantId();//商户号
            String privateKeyPath = wechatMerchantConfig.getPathPrivateKey();//商户 API 私钥路径
            String merchantSerialNumber = wechatMerchantConfig.getSerialNumber();//商户证书序列号
            String pubPath = wechatMerchantConfig.getPathPublicKey();//公钥路径
            String publicKeyId = wechatMerchantConfig.getPublicKeyId();//公钥id
            String apiV3Key = wechatMerchantConfig.getApiV3Key();//商户 APIV3 密钥
            //验证 属性不能为null
            Stream.of(merchantId, privateKeyPath, pubPath, publicKeyId, merchantSerialNumber, apiV3Key).forEach(Objects::requireNonNull);
            //创建配置
            RSAPublicKeyConfig config = new RSAPublicKeyConfig.Builder()
                    .merchantId(merchantId)
                    .privateKeyFromPath(privateKeyPath)
                    .publicKeyFromPath(pubPath)
                    .publicKeyId(publicKeyId)
                    .merchantSerialNumber(merchantSerialNumber)
                    .apiV3Key(apiV3Key)
                    .build();
            //创建http客户端
            AbstractHttpClient httpClient = new DefaultHttpClientBuilder()
                    .config(config)
                    .build();
            //加解密器
            AeadAesCipher aeadAesCipher = new AeadAesCipher(apiV3Key.getBytes(StandardCharsets.UTF_8));

            //回调 解析配置
            NotificationConfig notifyConfig = new RSAPublicKeyNotificationConfig.Builder()
                    .publicKeyFromPath(pubPath)
                    .publicKeyId(publicKeyId)
                    .apiV3Key(apiV3Key)
                    .build();
            //生成回调通知解析器
            NotificationParser parser = new NotificationParser(notifyConfig);
            //生成配置唯一值
            String configMD5 = StringHashGenerator.generateMD5(wechatMerchantConfig.toString());

            //config.createEncryptor(), config.createDecryptor(), aeadAesCipher,
            return new PubKeyWechatComplaintServiceImpl(wechatMerchantConfig, configMD5, config, httpClient, parser);
        }
    }
}
